/**对象模块 */

import { toString, isNullOrUndef } from './util'

/**
 * @name: deepClone
 * @cname: 深拷贝
 * @desc: 深度拷贝相应的数据
 * @param {*} obj
 * @panme: 深拷贝本身只针对较为复杂的object类型数据（常规名值对的无序对象{a:1}，数组[1,2,3]，以及函数）
 * @result: 当 let a=0 b=a 时 如果修改a=1 则b也会跟着改变 因为b复制的只是堆内存的地址 深拷贝则可实现单独开辟新的内存存放b
*/
export function deepClone(obj) {
    if ([null, undefined, NaN, false].includes(obj)) return obj;
    if (typeof obj !== "object" && typeof obj !== 'function') return obj;
    var o = Array.isArray(obj) ? [] : {};
    for (let i in obj) {
        if (obj.hasOwnProperty(i)) {
            o[i] = typeof obj[i] === "object" ? deepClone(obj[i]) : obj[i];
        }
    }
    return o;
}

/**
 * @name: contains
 * @cname: 判断是否包含
 * @desc: 判断对象是否包含另一个对象 包含则返回true 不包含则返回flase
 * @param {*}   a b
 * @panme: a={a:1,b:2} b=={a:1}
 * @result:  true
*/
export let contains = (a, b) => Object.entries(b).every(([k, v]) => a[k] === v)

/**
 * @name: convertObj2Str
 * @cname: 转化分割
 * @desc: 转换对象为String以&分割
 * @param {*}  params code
 * @panme: params={a:1,b:2} code='&'
 * @result: a=1&b=2
*/
export function convertObj2Str(params, code = '&') {
    if (!params) return ''
    return Object.keys(params).map(key => [key, params[key]].join('=')).join(code)
}

/**
 * @name: eq
 * @cname: 判断相等
 * @desc: 比较两个数据是否相等 支持基本类型和引用类型 相等则返回true 否则返回flase
 * @param {*}  a b
 * @panme: a=[1] b='1'
 * @result: flase
*/
export function eq(a, b) {
    if (a === b) return true
    if (typeof a !== 'object') return false
    if (toString(a) !== toString(b)) return false
    return Object.keys(a).every(k => eq(a[k], b[k]))
}

/**
 * @name: assign
 * @cname: 扩展对象
 * @desc: 使用一个新的对象的值覆盖旧有对象
 * @param {*}  target source
 * @panme: target={} source=assign(target,{a:1})
 * @result: source:{a:1} target:{a:1}
*/
export function assign(target, source) {
    keys(source).forEach(k => target[k] = source[k])
    return target
}

/**
 * @name: pairs
 * @cname: 转换
 * @desc: 把一个对象转变为一个[key, value]形式的数组。object()的逆向函数
 * @param {*}  obj deep
 * @panme: obj={one: 1, two: 2, three: 3}
 * @result: [["one", 1], ["two", 2], ["three", 3]]
*/
export function pairs(obj, deep = false) {
    if (!obj) return []
    return Object.entries(obj).map(([k, v]) => {
        if (deep && v && typeof v === 'object') v = pairs(v)
        return [k, v]
    })
}

/**
 * @name: convertStr2Obj
 * @cname:  分割转化
 * @desc: 以&分割String转化为对象
 * @param {*}  str code
 * @panme: str='a=1&b=2'
 * @result: {a: '1', b: '2'}
*/
export function convertStr2Obj(str, code = '&') {
    let obj = {}
    if (!str) return obj
    str.split(code).forEach(r => {
        let kv = r.split('=')
        obj[kv[0]] = kv[1]
    })
    return obj
}

/**
 * @name: isEmptyObj
 * @cname: 是否是空对象
 * @desc: 检查传入的对象是否是空对象 空则返回true 不空则返回false
 * @param {*}  obj 
 * @panme: obj={}
 * @result: true
*/
export let isEmptyObj = (obj) => !obj || !Object.keys(obj).length

/**
 * @name: keys
 * @cname: 截取字段名
 * @desc: 仅截取传入数据的字段名
 * @param {*}  obj 
 * @panme: obj={a:1,b:2,b:1}
 * @result: ['a', 'b']
*/
export function keys(obj) {
    if (!obj) throw 'obj is null'
    let arr = []
    for (const key in obj) {
        arr.push(key)
    }
    return arr
}

/**
 * @name: values
 * @cname: 去除字段
 * @desc: 去除字段为null或undefined不显示
 * @param {*}  obj hasNull 
 * @panme: obj=={ a: 1, b: null, c: undefined }
 * @result: [1]
*/
export function values(obj, hasNull) {
    hasNull = hasNull || false
    let res = []
    for (var key in obj) {
        let v = obj[key]
        if (v == undefined || v == null) {
            if (!hasNull) continue;
        }
        res.push(v)
    }
    return res
}

/**
 * @name: trimFields
 * @cname: 去空格
 * @desc: 将对象中的字符串类型的属性值，去空格常用于提交form表单时统一处理
 * @param {*}  params
 * @panme: params=={ 100: 'a', 2: '   b', 7: 'c' }
 * @result: {2: 'b', 7: 'c', 100: 'a'}
*/
export function trimFields(params) {
    return keys(params).reduce((o, key) => {
        let val = params[key]
        o[key] = typeof val === 'string' ? val.trim() : val
        return o;
    }, {});
}

/**
 * @name: pickObj
 * @cname: 提取字段
 * @desc: 从对象或者对象数组中择出你要的字段
 * @param {*} obj 传入对象 keys 传入字段
 * @panme: obj:{ a: 1, b: 2, c: 3, d: 4 } keys:['b','d']
 * @result:  [{  b: 2, d: 4 }]
*/
export function pickObj(obj, keys) {
    return keys.reduce((o, r) => {
        let val = obj[r];
        !isNullOrUndef(val) && (o[r] = val)
        return o
    }, {})
}